Disable frame sync for GtkPlug
authorOwen W. Taylor <otaylor@fishsoup.net>
Wed, 26 Jun 2013 14:05:38 +0000 (10:05 -0400)
committerOwen W. Taylor <otaylor@fishsoup.net>
Mon, 22 Jul 2013 22:36:58 +0000 (18:36 -0400)
Plug windows weren't redrawing properly because the embedded
window was expecting to get messages for each frame from the
compositor, but the compositor doesn't know about embedded
windows. Simply disable frame sync for GtkPlug's GdkWindow -
extending XEMBED to handle frame sync isn't interesting
at this point.

A new API gdk_x11_window_set_frame_sync_enabled() is added
to allow this to be done.

https://bugzilla.gnome.org/show_bug.cgi?id=701613

gdk/x11/gdkwindow-x11.c
gdk/x11/gdkwindow-x11.h
gdk/x11/gdkx11window.h
gtk/gtkplug.c

index 3fe545c12527d32c83a46460b128af4fc8694efd..8eca50c61854e2c42380770fa7c800d372974e92 100644 (file)
@@ -157,6 +157,7 @@ gdk_window_impl_x11_init (GdkWindowImplX11 *impl)
   impl->device_cursor = g_hash_table_new_full (NULL, NULL,
                                                NULL, g_object_unref);
   impl->window_scale = 1;
+  impl->frame_sync_enabled = TRUE;
 }
 
 GdkToplevelX11 *
@@ -403,7 +404,8 @@ gdk_x11_window_end_frame (GdkWindow *window)
                       impl->toplevel->extended_update_counter,
                       impl->toplevel->current_counter_value);
 
-      if (gdk_x11_screen_supports_net_wm_hint (gdk_window_get_screen (window),
+      if (impl->frame_sync_enabled &&
+          gdk_x11_screen_supports_net_wm_hint (gdk_window_get_screen (window),
                                               gdk_atom_intern_static_string ("_NET_WM_FRAME_DRAWN")))
         {
           impl->toplevel->frame_pending = TRUE;
@@ -5443,6 +5445,37 @@ gdk_x11_window_get_scale_factor (GdkWindow *window)
   return impl->window_scale;
 }
 
+/**
+ * gdk_x11_window_set_frame_sync_enabled:
+ * @window: (type GdkX11Window): a native #GdkWindow
+ * @frame_sync_enabled: whether frame-synchronization should be enabled
+ *
+ * This function can be used to disable frame synchronization for a window.
+ * Normally frame synchronziation will be enabled or disabled based on whether
+ * the system has a compositor that supports frame synchronization, but if
+ * the window is not directly managed by the window manager, then frame
+ * synchronziation may need to be disabled. This is the case for a window
+ * embedded via the XEMBED protocol.
+ *
+ * Since: 3.8
+ */
+void
+gdk_x11_window_set_frame_sync_enabled (GdkWindow *window,
+                                       gboolean   frame_sync_enabled)
+{
+  /* Try to ensure the window has a native window */
+  if (!_gdk_window_has_impl (window))
+    gdk_window_ensure_native (window);
+
+  if (!GDK_WINDOW_IS_X11 (window))
+    {
+      g_warning (G_STRLOC " drawable is not a native X11 window");
+      return;
+    }
+
+  GDK_WINDOW_IMPL_X11 (window->impl)->frame_sync_enabled = FALSE;
+}
+
 static void
 gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
 {
index 1c50cf486132777d1c9f0e44f450e5a864804d78..92db3d819219b63eef57a5b19ebc2555269c78c7 100644 (file)
@@ -74,6 +74,7 @@ struct _GdkWindowImplX11
                            * unset during resizing and scaling */
   guint override_redirect : 1;
   guint frame_clock_connected : 1;
+  guint frame_sync_enabled : 1;
 
   cairo_surface_t *cairo_surface;
 
@@ -176,6 +177,8 @@ GType gdk_window_impl_x11_get_type (void);
 
 void            gdk_x11_window_set_user_time        (GdkWindow *window,
                                                     guint32    timestamp);
+void            gdk_x11_window_set_frame_sync_enabled (GdkWindow *window,
+                                                       gboolean   frame_sync_enabled);
 
 GdkToplevelX11 *_gdk_x11_window_get_toplevel        (GdkWindow *window);
 void            _gdk_x11_window_tmp_unset_bg        (GdkWindow *window,
index bf4d5538731a40e32f0afe0d3f04136e3b9cf2d8..1503402eba0a608b2a13dcc27addd33a24c3a2c8 100644 (file)
@@ -71,6 +71,10 @@ void     gdk_x11_window_set_hide_titlebar_when_maximized (GdkWindow *window,
 GDK_AVAILABLE_IN_ALL
 void     gdk_x11_window_move_to_current_desktop (GdkWindow   *window);
 
+GDK_AVAILABLE_IN_3_8
+void     gdk_x11_window_set_frame_sync_enabled (GdkWindow *window,
+                                                gboolean   frame_sync_enabled);
+
 /**
  * GDK_WINDOW_XDISPLAY:
  * @win: a #GdkWindow.
index 788be1a71e44c07eea6507a0c0a6978f01702c99..c2fb49304bd97ae2ebf463ac2f2c8064d731f6d9 100644 (file)
@@ -1053,6 +1053,13 @@ gtk_plug_realize (GtkWidget *widget)
       else /* If it's a passive plug, we use the root window */
         gdk_window = gdk_window_new (gtk_widget_get_root_window (widget),
                                      &attributes, attributes_mask);
+      /* Because the window isn't known to the window manager,
+       * frame sync won't work. In theory, XEMBED could be extended
+       * so that embedder did frame sync like a window manager, but
+       * it's just not worth the effort considering the current
+       * minimal use of XEMBED.
+       */
+      gdk_x11_window_set_frame_sync_enabled (gdk_window, FALSE);
       gtk_widget_set_window (widget, gdk_window);
 
       gdk_display_sync (gtk_widget_get_display (widget));